package com.personal.system.service.impl.sys;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.personal.model.system.SysUser;
import com.personal.system.custom.Constants;
import com.personal.system.entity.sys.OnlineUser;
import com.personal.system.entity.RedisCacheInfoDTO;
import com.personal.system.entity.sys.ServerInfo;
import com.personal.system.mapper.sys.SysDeptMapper;
import com.personal.system.service.sys.MonitorApplicationService;
import lombok.NonNull;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MonitorApplicationServiceImpl implements MonitorApplicationService {

    @NonNull
    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private SysDeptMapper deptMapper;

    @Override
    public RedisCacheInfoDTO getRedisCacheInfo() {

        Properties info = (Properties)redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
        Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize);

        if(commandStats == null) {
            throw new RuntimeException("找不到对应的redis信息。");
        }

        RedisCacheInfoDTO cacheInfo = new RedisCacheInfoDTO();
        cacheInfo.setInfo(info);
        cacheInfo.setDbSize(dbSize);
        cacheInfo.setCommandStats(new ArrayList<>());

        commandStats.stringPropertyNames().forEach(key -> {
            String property = commandStats.getProperty(key);
            RedisCacheInfoDTO.CommonStatusDTO commonStatus = new RedisCacheInfoDTO.CommonStatusDTO();
            commonStatus.setName(StrUtil.removePrefix(key, "cmdstat_"));
            commonStatus.setValue(StrUtil.subBetween(property, "calls=", ",usec"));
            cacheInfo.getCommandStats().add(commonStatus);
        });

        return cacheInfo;
    }

    @Override
    public ServerInfo getServerInfo() {

        return ServerInfo.fillInfo();
    }

    @Override
    public List<OnlineUser> getOnlineUserList(String userName, String ipaddr) {

        Collection<String> keys = redisTemplate.keys(Constants.LOGIN_USER_KEY+"*");
        for (String key : keys) {
            Object o = redisTemplate.opsForValue().get(key);
        }
        List<OnlineUser> allOnlineUsers = keys.stream().map(
                o -> mapLoginUserToUserOnline(redisTemplate.opsForValue().get(o)))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        List<OnlineUser> filteredOnlineUsers = allOnlineUsers.stream()
                .filter(o -> StrUtil.isEmpty(userName) || userName.equals(o.getUserName()))
                .filter( o -> StrUtil.isEmpty(ipaddr) || ipaddr.equals(o.getIpaddr())).collect(Collectors.toList());

        Collections.reverse(filteredOnlineUsers);
        return filteredOnlineUsers;
    }

    public OnlineUser mapLoginUserToUserOnline(Object user) {
        if (user == null) {
            return null;
        }
        JSONObject object = JSON.parseObject(user.toString());
        OnlineUser onlineUser = new OnlineUser();
//        onlineUser.setTokenId(user.getToken());
        onlineUser.setUserName(object.getString("username"));
//        onlineUser.setIpaddr(user.getLoginInfo().getIpAddress());
//        onlineUser.setLoginLocation(user.getLoginInfo().getLocation());
//        onlineUser.setBrowser(user.getLoginInfo().getBrowser());
//        onlineUser.setOs(user.getLoginInfo().getOperationSystem());
//        onlineUser.setLoginTime(user.getLoginTime());
        SysUser sysUser = JSON.parseObject(object.getString("sysUser"), SysUser.class);
        onlineUser.setDeptName(deptMapper.selectById(sysUser.getDeptId()).getName());

        return onlineUser;
    }

    @Override
    public boolean forceLogout(String userName) {

        return redisTemplate.delete(Constants.LOGIN_USER_KEY+":"+userName);
    }
}
